package de.openkanban.server.controller;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dozer.DozerBeanMapper;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import de.openkanban.server.domain.Activity;
import de.openkanban.server.domain.Board;
import de.openkanban.server.domain.History;
import de.openkanban.server.domain.User;
import de.openkanban.server.interceptor.annotation.SecurityInterception;
import de.openkanban.server.service.ActivityService;
import de.openkanban.server.service.BoardService;
import de.openkanban.server.service.HistoryService;
import de.openkanban.server.service.UserService;
import de.openkanban.server.session.OpenKanbanSessionAttributes;
import de.openkanban.shared.dto.ActivityDto;
import de.openkanban.shared.dto.BoardDto;
import de.openkanban.shared.dto.HistoryDto;
import de.openkanban.shared.dto.StatusDto;
import de.openkanban.shared.dto.UserDto;
import de.openkanban.shared.util.StatusCodes;

@Controller
@RequestMapping(value = "/board")
public class BoardController {

	@Autowired
	private BoardService boardService;

	@Autowired
	private UserService userService;

	@Autowired
	private ActivityService activityService;

	@Autowired
	private HistoryService historyService;

	@Autowired
	private OpenKanbanSessionAttributes sessionAttributes;

	@Autowired
	private DozerBeanMapper mapper;

	@RequestMapping(method = RequestMethod.POST, value = "/all")
	@ResponseBody
	@SecurityInterception
	public List<BoardDto> getAllBoards(HttpServletRequest req, HttpServletResponse resp) {
		List<Board> boardList = boardService.getAll();

		List<BoardDto> boardDtoList = new ArrayList<BoardDto>();
		for (Board board : boardList) {
			boardDtoList.add(mapper.map(board, BoardDto.class));
		}

		return boardDtoList;
	}

	@RequestMapping(method = RequestMethod.POST, value = "/{boardId}")
	@ResponseBody
	@SecurityInterception
	public BoardDto getBoardById(@PathVariable Long boardId, HttpServletRequest req, HttpServletResponse resp) {
		Board board = boardService.getBoardById(boardId);
		return mapper.map(board, BoardDto.class);
	}

	@RequestMapping(method = RequestMethod.POST, value = "/user/{userId}")
	@ResponseBody
	@SecurityInterception
	public BoardDto getDefaultBoard(@PathVariable Long userId, HttpServletRequest req, HttpServletResponse resp) {
		Board board = boardService.getDefaultBoardByUserId(userId);
		if (board != null) {
			return mapper.map(board, BoardDto.class);
		}
		return new BoardDto();
	}

	@RequestMapping(method = RequestMethod.POST, value = "/{currentBoardId}/{userId}/forward")
	@ResponseBody
	@SecurityInterception
	public BoardDto getDefaultBoardForward(@PathVariable Long currentBoardId, @PathVariable Long userId, HttpServletRequest req,
			HttpServletResponse resp) {
		Long nextBoardId = boardService.getNextBoardId(currentBoardId, userId);
		BoardDto nextBoardDto = new BoardDto();
		nextBoardDto.setBoardId(nextBoardId);
		return nextBoardDto;
	}

	@RequestMapping(method = RequestMethod.POST, value = "/{currentBoardId}/{userId}/backward")
	@ResponseBody
	@SecurityInterception
	public BoardDto getDefaultBoardBackward(@PathVariable Long currentBoardId, @PathVariable Long userId, HttpServletRequest req,
			HttpServletResponse resp) {
		Long priorBoardId = boardService.getPriorBoardId(currentBoardId, userId);
		BoardDto priorBoardDto = new BoardDto();
		priorBoardDto.setBoardId(priorBoardId);
		return priorBoardDto;
	}

	@RequestMapping(method = RequestMethod.POST, value = "/create")
	@ResponseBody
	@SecurityInterception
	public BoardDto createBoard(BoardDto boardDto, HttpServletRequest req, HttpServletResponse resp) {
		Board board = mapper.map(boardDto, Board.class);
		board = boardService.createBoard(board, sessionAttributes.getUserId(req));
		return mapper.map(board, BoardDto.class);
	}

	@RequestMapping(method = RequestMethod.POST, value = "/update")
	@ResponseBody
	@SecurityInterception
	public BoardDto updateBoard(BoardDto boardDto, HttpServletRequest req, HttpServletResponse resp) {
		Board board = mapper.map(boardDto, Board.class);
		board = boardService.updateBoard(board);
		return mapper.map(board, BoardDto.class);
	}

	@RequestMapping(method = RequestMethod.POST, value = "{parentBoardId}/activity/all")
	@ResponseBody
	@SecurityInterception
	public List<ActivityDto> getAllActivities(@PathVariable Long parentBoardId, HttpServletRequest req, HttpServletResponse resp) {
		List<Activity> activityList = activityService.getAllByBoardId(parentBoardId);
		List<ActivityDto> activityDtoList = new ArrayList<ActivityDto>();
		ActivityDto activityDto;
		for (Activity activity : activityList) {
			activityDto = mapper.map(activity, ActivityDto.class);
			activityDtoList.add(activityDto);
		}

		return activityDtoList;
	}

	@RequestMapping(method = RequestMethod.POST, value = "{parentBoardId}/activity/add")
	@ResponseBody
	@SecurityInterception
	public ActivityDto addActivityToBoard(@PathVariable Long parentBoardId, ActivityDto activityDto, HttpServletRequest req,
			HttpServletResponse resp) {
		Activity activity = mapper.map(activityDto, Activity.class);
		activity = boardService.addActivityToBoard(parentBoardId, activity);
		return mapper.map(activity, ActivityDto.class);
	}

	@RequestMapping(method = RequestMethod.POST, value = "{parentBoardId}/contact/add/{userIdToAdd}")
	@ResponseBody
	@SecurityInterception
	public StatusDto addContactToBoard(@PathVariable Long parentBoardId, @PathVariable Long userIdToAdd, HttpServletRequest req,
			HttpServletResponse resp) {
		User userToAdd = userService.getUser(userIdToAdd);
		StatusCodes statusCode = boardService.addContactToBoard(parentBoardId, userToAdd);
		return new StatusDto(statusCode.getStatusCode(), statusCode.getStatusText());
	}

	@RequestMapping(method = RequestMethod.POST, value = "{parentBoardId}/contact/remove/{userIdToRemove}")
	@ResponseBody
	@SecurityInterception
	public StatusDto removeContactFromBoard(@PathVariable Long parentBoardId, @PathVariable Long userIdToRemove,
			HttpServletRequest req, HttpServletResponse resp) {
		StatusCodes statusCode = boardService.removeContactFromBoard(parentBoardId, userIdToRemove);
		return new StatusDto(statusCode.getStatusCode(), statusCode.getStatusText());
	}

	@RequestMapping(method = RequestMethod.GET, value = "/{parentBoardId}/contact/get")
	@ResponseBody
	@SecurityInterception
	@Transactional
	public UserDto[] getContacts(@PathVariable Long parentBoardId, HttpServletRequest req, HttpServletResponse resp) throws Exception {
		Board parentBoard = boardService.getBoardById(parentBoardId);

		List<UserDto> userDtoList = new ArrayList<UserDto>();
		for (User user : parentBoard.getBoardUser()) {
			userDtoList.add(mapper.map(user, UserDto.class));
		}

		return userDtoList.toArray(new UserDto[] {});

	}

	@RequestMapping(method = RequestMethod.GET, value = "/{parentBoardId}/history/get")
	@ResponseBody
	@SecurityInterception
	@Transactional
	public HistoryDto[] getHistory(@PathVariable Long parentBoardId, HttpServletRequest req, HttpServletResponse resp) throws Exception {
		History[] historyArr = historyService.getFullBoardHistory(parentBoardId);

		List<HistoryDto> historyDtoList = new ArrayList<HistoryDto>();
		for (History history : historyArr) {
			HistoryDto historyDto = mapper.map(history, HistoryDto.class);
			User user = userService.getUser(history.getUserId());
			historyDto.setNamensKuerzel(user.getNamensKuerzel());
			historyDto.setHistoryActionValue(history.getHistoryAction().getActionIcon());

			DateTime dateTime = new DateTime(history.getHistoryDate());
			String formatedDate = DateTimeFormat.shortDateTime().print(dateTime.getMillis());
			historyDto.setHistoryDateTime(formatedDate);

			historyDtoList.add(historyDto);
		}

		return historyDtoList.toArray(new HistoryDto[] {});

	}

	public BoardService getBoardService() {
		return boardService;
	}

	public void setBoardService(BoardService boardService) {
		this.boardService = boardService;
	}

}
